//
// Created by user on 20-4-14.
//

#ifndef _APIC_H_
#define _APIC_H_

#include "../ProcessManagement/Cpu.h"
#include "../GeneralLibrary/Printf.h"
#include "../MemoryManagement/Malloc.h"
#include "Interrupt.h"
#include "../ProcessManagement/SMP.h"

/*=============================== 宏变量定义区 =============================*/

// 投递模式
#define	APIC_ICR_IOAPIC_Fixed 		 0	    // LAPIC	IOAPIC 	ICR
#define	IOAPIC_ICR_Lowest_Priority 	 1	    // IOAPIC 	ICR
#define	APIC_ICR_IOAPIC_SMI		     2	    // LAPIC	IOAPIC 	ICR

#define	APIC_ICR_IOAPIC_NMI		     4	    // LAPIC	IOAPIC 	ICR
#define	APIC_ICR_IOAPIC_INIT		 5	    // LAPIC	IOAPIC 	ICR
#define	ICR_Start_Up			     6	    // ICR
#define	IOAPIC_ExtINT			     7	    // IOAPIC

// 定时模式
#define APIC_LVT_Timer_One_Shot		0
#define APIC_LVT_Timer_Periodic		1
#define APIC_LVT_Timer_TSC_Deadline	2

// 屏蔽
#define APIC_ICR_IOAPIC_Masked		1
#define APIC_ICR_IOAPIC_UN_Masked	0

// 桥接模式
#define APIC_ICR_IOAPIC_Edge		0
#define APIC_ICR_IOAPIC_Level		1

// 投递状态
#define APIC_ICR_IOAPIC_Idle		    0
#define APIC_ICR_IOAPIC_Send_Pending	1

// destination mode
#define ICR_IOAPIC_DELV_PHYSICAL	0
#define ICR_IOAPIC_DELV_LOGIC		1

// destination shorthand
#define ICR_No_Shorthand		    0
#define ICR_Self			        1
#define ICR_ALL_INCLUDE_Self		2
#define ICR_ALL_EXCLUDE_Self		3

// 等级
#define ICR_LEVEL_DE_ASSERT		0
#define ICR_LEVLE_ASSERT		1

// 远程IRR
#define APIC_IOAPIC_IRR_RESET		0
#define APIC_IOAPIC_IRR_ACCEPT		1

// pin polarity
#define APIC_IOAPIC_POLARITY_HIGH	0
#define APIC_IOAPIC_POLARITY_LOW	1

/*=============================== 结构体重命名区 =============================*/

typedef struct IOAPICMapStruct IOAPICMap;
typedef struct IOAPICRETEntryStruct IOAPICRETEntry;

/*================================ 结构体声明区 ==============================*/

// I/O APIC 映射结构体
struct IOAPICMapStruct {
    unsigned int physicalAddress;           // 间接访问寄存器的物理基地址
    unsigned char *virtualIndexAddress;     // 间接访问寄存器的索引寄存器的线性地址
    unsigned int *virtualDataAddress;       // 间接访问寄存器的数据寄存器的线性地址
    unsigned int *virtualEOIAddress;        // 间接访问寄存器的EOI寄存器的线性地址
};

struct IOAPICRETEntryStruct {
    unsigned int vector    :8,    //0~7
            deliverMode    :3,    //8~10
            destMode    :1,    //11
            deliver_status    :1,    //12
            polarity:1,    //13
            irr    :1,    //14
            trigger    :1,    //15
            mask    :1,    //16
            reserved:15;    //17~31

    union {
        struct {
            unsigned int reserved1    :24,    //32~55
                    phy_dest    :4,    //56~59
                    reserved2    :4;    //60~63
        } physical;

        struct {
            unsigned int reserved1    :24,    //32~55
                    logical_dest    :8;    //56~63
        } logical;
    } destination;
}__attribute__((packed));

struct INT_CMD_REG {
    unsigned int vector    :8,    //0~7
            deliverMode    :3,    //8~10
            destMode    :1,    //11
            deliverStatus    :1,    //12
            res_1    :1,    //13
            level    :1,    //14
            trigger    :1,    //15
            res_2    :2,    //16~17
            destShorthand    :2,    //18~19
            res_3    :12;    //20~31

    union {
        struct {
            unsigned int res_4    :24,    //32~55
                    destField    :8;    //56~63
        } apicDestination;

        unsigned int x2apicDestination;    //32~63
    } destination;

}__attribute__((packed));

/*================================ 函数声明区 ===============================*/
/**
 * 初始化 APIC 设备
 */
void APICDeviceInit();

/**
 * 初始化 Local APIC
 */
void LocalAPICInit();

/**
 * 将 I/O APIC 的页表进行映射
 */
void IOAPICPageTableRemap();

/**
 * 读取 RTE 寄存器的值
 * @param index 要读取的索引
 * @return 返回该寄存器对应索引的值
 */
unsigned long ioapicRTERead(unsigned char index);

/**
 * 向 RTE 寄存器写入值
 * @param index 要写入的索引
 * @param value 要写入的值
 */
void ioapicRTEWrite(unsigned char index, unsigned long value);

/**
 * 初始化 I/O APIC
 */
void IOAPICInit();

/**
 * 使能函数
 * @param irq 中断号
 */
void IOAPICEnable(unsigned long irq);

/**
 * 禁止函数
 * @param irq 中断号
 */
void IOAPICDisable(unsigned long irq);

/**
 * 安装函数
 * @param irq 中断号
 * @param arg 参数
 * @return 返回 0 或 1
 */
unsigned long IOAPICInstall(unsigned long irq, void *arg);

/**
 * 卸载函数
 * @param irq 中断号
 */
void IOAPICUninstall(unsigned long irq);

/**
 * 等级应答
 * @param irq 中断号
 */
void IOAPICLevelAck(unsigned long irq);

/**
 * 标记应答
 * @param irq 中断号
 */
void IOAPICEdgeAck(unsigned long irq);

/**
 * 等级加标记应答
 * @param irq 中断号
 */
void LocalAPICEdgeLevelAck(unsigned long irq);

/**
 * APIC专用的中断输出函数
 * @param regs 寄存器
 * @param nr 中断号
 */
void doIRQ(PerformSite *regs, unsigned long nr);

#endif //_APIC_H_
